//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include <xllp_dmac.h>
#include <bulverde.h>
#include "ccamera.h"

typedef struct tagRECT {
    Int32 left;
    Int32 top;
    Int32 right;
    Int32 bottom;
} RECT, *PRECT;

#if (_TEST_TYPE == 41)      /* Test for Runtime of ISR */
    #define SAMPLETIMES 50
    UInt32 uTimerStart, uTimerEnd;
    UInt32 ulCapturePhotoTime[SAMPLETIMES];
    Int32 nCapturePhotoSampleCounter = 0;
#endif //_TEST_TYPE == 41

class CCamera : public CDeviceDriver {
    public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);
    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);
    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose();
    Boolean   Install();

public:
     CamDrv_Context CurrentContext;
};


ECode CCamera::Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode CCamera::Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

void PoSetCameraPowerOn(Boolean PowerOn);
void PoSetLcdPowerOn(Boolean PowerOn);
ECode CCamera::Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent)
{
    ECode ec = NOERROR;
    Camera_Format *pFormat;

    switch (nControlCode) {
        case 0:
            // Initialize camera device
            ec = CamDrv_Init(&CurrentContext);
            break;

        case 1:
            // Quit camera device
            CamDrv_Quit(&CurrentContext);
            CurrentContext.CaptureStatus = CamDrv_Status_Closed;
            break;

        case 2:
            // Get photo information and data
            // If continue snap is set, maybe there are more than 1 photo
#if (_TEST_TYPE == 41)
    uTimerStart = OSCR0;
#endif //_TEST_TYPE == 41
            if (pOutBuffer == NULL) {
                ec =  E_INVALID_ARGUMENT;
                break;
            }
            if (pOutBuffer->GetCapacity() < (int)sizeof(Camera_Photo)) {
                ec = E_OUT_OF_MEMORY;
                break;
            }
            if (CurrentContext.CaptureStatus == CamDrv_Status_Preview) {
                CamDrv_StopVideoCapture(&CurrentContext);
            }
//            ec = CamDrv_GetSnapFrames((Camera_Photo *)(char *)ebbOutData);
            CurrentContext.CaptureStatus = CamDrv_Status_Still;
            ec = CamDrv_StartStillCapture(&CurrentContext);
            if (FAILED(ec)) return ec;

            ec = CamDrv_GetStillPhoto(&CurrentContext, (Camera_Photo *)pOutBuffer->GetPayload());
            pOutBuffer->SetUsed(sizeof(Camera_Photo));
#if (_TEST_TYPE == 41)
    uTimerEnd = OSCR0;
    if (nCapturePhotoSampleCounter >= SAMPLETIMES) nCapturePhotoSampleCounter = 0;
    ulCapturePhotoTime[nCapturePhotoSampleCounter++] = \
                            (uTimerEnd >= uTimerStart) ? \
                            (uTimerEnd - uTimerStart) : \
                            ((UInt32)0xFFFFFFFF - uTimerStart + uTimerEnd);
#endif //_TEST_TYPE == 42
            break;

        case 3:
            // Begin preview
            if (inBuffer.GetCapacity() < (int)sizeof(RECT)) {
                ec = E_OUT_OF_MEMORY;
                break;
            }
            if (CurrentContext.CaptureStatus == CamDrv_Status_Preview) {
                break;
            }
            CurrentContext.CaptureStatus = CamDrv_Status_Preview;
            ec = CamDrv_StartVideoCapture(&CurrentContext);
            PoSetLcdPowerOn(TRUE);//tell power manager not to suspend lcd
            PoSetCameraPowerOn(TRUE);//tell power manager not to suspend camera
            break;

        case 4:
            // Stop preview
            if (CurrentContext.CaptureStatus == CamDrv_Status_Preview) {
                CamDrv_StopVideoCapture(&CurrentContext);
            }
            CurrentContext.CaptureStatus = CamDrv_Status_Unprepared;
            PoSetCameraPowerOn(FALSE);//tell power manager to suspend camera
            PoSetLcdPowerOn(FALSE);//tell power manager to suspend LCD
            break;

        case 5:
            // Release the memory of frames, except the default preview buffer.
            CamDrv_ReleaseFrames(&CurrentContext);
            break;

        case 6:
            // Set many formats for camera device, such as photo quality, brightness ...
            if (inBuffer.GetCapacity() < (int)sizeof(Camera_Format)) {
                ec = E_OUT_OF_MEMORY;
                break;
            }

            pFormat = (Camera_Format *)inBuffer.GetPayload();

            ec = CamDrv_SetAppFormat(&CurrentContext, pFormat->nID,
                    pFormat->wParam, pFormat->lParam);
            break;

        case 7:
            // Get many formats for camera device, such as photo quality, brightness ...
            if (pOutBuffer == NULL) {
                ec =  E_INVALID_ARGUMENT;
                break;
            }
            if (inBuffer.GetCapacity() < (int)sizeof(int) ||
                pOutBuffer->GetCapacity() < (int)sizeof(Camera_Format)) {
                ec = E_OUT_OF_MEMORY;
                break;
            }

            pFormat = (Camera_Format *)pOutBuffer->GetPayload();
            pFormat->nID = *(int *)inBuffer.GetPayload();

            ec = CamDrv_GetAppFormat(&CurrentContext, pFormat->nID,
                    &pFormat->wParam, &pFormat->lParam);
            pOutBuffer->SetUsed(sizeof(Camera_Format));
            break;

        // Power management code
        case 1000:
            if (CurrentContext.CaptureStatus != CamDrv_Status_Closed) {
                if (CurrentContext.CaptureStatus == CamDrv_Status_Preview) {
                    CamDrv_StopVideoCapture(&CurrentContext);
                    CurrentContext.CaptureStatus = CamDrv_Status_PreviewPaused;
                }
                CamDrv_SaveFormat(&CurrentContext);
                CamDrv_CloseHardware(&CurrentContext);
            }
            break;

        case 1001:
        case 1002:
            if (CurrentContext.CaptureStatus != CamDrv_Status_Closed) {
                CamDrv_SetDefaultFormat(&CurrentContext);
                CamDrv_OpenHardware(&CurrentContext);
                CamDrv_ResumeFormat(&CurrentContext);
                if (CurrentContext.CaptureStatus == CamDrv_Status_PreviewPaused) {
                    CurrentContext.CaptureStatus = CamDrv_Status_Preview;
                    CamDrv_StartVideoCapture(&CurrentContext);
                }
            }
            break;
#if (_TEST_TYPE == 41)
        case 4100:
            memcpy(pOutBuffer->GetPayload(),
                    ul_DmaChYIsrTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
        case 4101:
            memcpy(pOutBuffer->GetPayload(),
                    ul_DmaChCbIsrTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
        case 4102:
            memcpy(pOutBuffer->GetPayload(),
                    ul_DmaChCrIsrTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;

        case 4103:
            memcpy(pOutBuffer->GetPayload(),
                    ulCapturePhotoTime,
                    SAMPLETIMES * sizeof(UInt32));
            pOutBuffer->SetUsed(SAMPLETIMES * sizeof(UInt32));
            ec = NOERROR;
            break;
#endif // _TEST_TYPE 41
        default :
            ec = E_NOT_IMPLEMENTED;
            break;
    }

    return ec;
}

void CCamera::Dispose()
{
    delete this;
}

Boolean CCamera::Install()
{
    // Clear current camera context
    memset(&CurrentContext, 0, sizeof(CamDrv_Context));

    CurrentContext.CaptureStatus = CamDrv_Status_Closed;

    if (FAILED(CamDrv_Install(&CurrentContext))) return FALSE;
    return TRUE;
}

EXTERN IDeviceDriver * CDECL CreateCamera(uint_t uDeviceNo, void *pvParameter)
{
    CCamera *pCamera = new CCamera;

    if (!pCamera) goto ErrorExit;
    if (!pCamera->Install()) goto ErrorExit;

    kprintf("Add Camera OK!\n");

    return pCamera;

ErrorExit:
    kprintf("Add Camera Failed!\n");
    return NULL;
}
